﻿using System;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;

namespace hello.csharp.helper
{
    public class PasswordHelper
    {
        public static string CreateHash(string pwSource, string pepper)
        {
            var bs = Encoding.ASCII.GetBytes(pepper);
            var output = PBKDF2(pwSource, bs, 512, 128);
            return Convert.ToBase64String(output);
        }

        /// <summary>
        /// Computes the PBKDF2-SHA1 hash of a password.
        /// </summary>
        /// <param name="password">The password.</param>
        /// <param name="salt">The salt.</param>
        /// <param name="iterations">PBKDF2迭代次数。</param>
        /// <param name="outputBytes">要生成的伪随机密钥字节数。</param>
        /// <returns>填充有伪随机密钥字节的字节数组。</returns>
        private static byte[] PBKDF2(string password, byte[] salt, int iterations, int outputBytes)
        {
            Rfc2898DeriveBytes pbkdf2 = new Rfc2898DeriveBytes(password, salt);
            pbkdf2.IterationCount = iterations;
            return pbkdf2.GetBytes(outputBytes);
        }

        /// <summary>
        /// Compares two byte arrays in length-constant time. This comparison
        /// method is used so that password hashes cannot be extracted from
        /// on-line systems using a timing attack and then attacked off-line.
        /// </summary>
        /// <param name="a">The first byte array.</param>
        /// <param name="b">The second byte array.</param>
        /// <returns>True if both byte arrays are equal. False otherwise.</returns>
        public static bool SlowEquals(byte[] a, byte[] b)
        {
            uint diff = (uint)a.Length ^ (uint)b.Length;
            for (int i = 0; i < a.Length && i < b.Length; i++)
                diff |= (uint)(a[i] ^ b[i]);
            return diff == 0;
        }
    }
}